package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoAsyncService;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: 李旭
 * @create: 2021-07-20 15:25
 **/
@Service
public class CartInfoServiceImpl implements CartInfoService {
    @Autowired
    private RedisTemplate redisTemplate;//购物车保存在缓存中使用的数据类型  五大数据类型
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartInfoAsyncService cartInfoAsyncService;

    //加入购物车
    @Override
    public void addCart(Long skuId, Integer skuNum, String userId) {
        //用户的在缓存中的Key
        String cacheKeyByUser = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        //Hash  User id 1 name z3 age 23  ..
        //RedisHash   HashMap  K V
        // K : 用户ID  HK：skuId(商品） HV:数量
        //Map user:3:cart = new HashMap
        //K.put(HK,HV)
   /*     redisTemplate.opsForHash().put(RedisConst.USER_KEY_PREFIX + userId
         + RedisConst.USER_CART_KEY_SUFFIX,skuId.toString(),CartInfo );// K HK HV*/

        //1:根据skuId 查询当前用户的购物车(一个）  从缓存中获取
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKeyByUser, skuId.toString());
        if (null != cartInfo) {
            //2：此商品已经有了  追加数量即可
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //选中
            cartInfo.setIsChecked(CartInfo.YESCHECKED);
            //DB  更新   update   异步
            //cartInfoMapper.updateById(cartInfo);//开启子线程
            System.out.println("我是主线程:" + Thread.currentThread().getName());
            cartInfoAsyncService.updateAsync(cartInfo);
        } else {
            //3:此商品没有   添加新商品
            cartInfo = new CartInfo();
            //购物车中数据填充
            //基本数据以外 还有记录查询当前此商品最新价格 实时价格
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuInfo.getId());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            //选中 默认
            cartInfo.setIsChecked(CartInfo.YESCHECKED);
            //数量
            cartInfo.setSkuNum(skuNum);
            //加入购物车时的价格
            BigDecimal price = productFeignClient.getPrice(skuId);
            cartInfo.setCartPrice(price);
            //实时价格
            cartInfo.setSkuPrice(price);
            //DB 添加  insert  将自动增长的ID进行返回  异步  JUC包下 1.8版本 异步编排  Spring异步 注解开启子线程
            //cartInfoMapper.insert(cartInfo);//开启子线程
            System.out.println("我是主线程:" + Thread.currentThread().getName());
            cartInfoAsyncService.insertAsync(cartInfo);//SQL 慢
        }
        //4:双写
        //保存缓存 （主）
        redisTemplate.opsForHash().put(RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX, skuId.toString(), cartInfo);
    }


    //查询一个购物车
    @Override
    public CartInfo getCartInfoBySkuId(Long skuId) {
        //全局获取Request对象方式  任意位置想获取request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = requestAttributes.getRequest();
        //HttpServletResponse response = requestAttributes.getResponse();
        //真实用户ID
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        return (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId.toString());
    }

    //去购物车结算
    @Override
    @Transactional
    public List<CartInfo> cartList(String userId, String userTempId) {
        //1:未登录 userId没有  userTempId 肯定有
        if (!StringUtils.isEmpty(userId)) {
            //登录了 有userId
            if (!StringUtils.isEmpty(userTempId)) {
                //有临时用户ID
                return mergeCartList(userId, userTempId);
            } else {
                //返回真实用户的购物车集合
                return getCartInfoList(userId);
            }
        } else {
            //2:未登录 userId没有  userTempId 不一定
            if (!StringUtils.isEmpty(userTempId)) {
                //有临时用户ID
                return getCartInfoList(userTempId);
            } else {
                return null;
            }
        }
    }

    //选中
    @Override
    @Transactional //事务
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);// update cart_info set is_checkec = 1 where
        cartInfoMapper.update(cartInfo,
                new QueryWrapper<CartInfo>().eq("user_id", userId)
                        .eq("sku_id", skuId));
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        //更新Redis
        cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheKey, skuId.toString(), cartInfo);

    }

    @Override
    public List<CartInfo> getCartInfoCheckedList(String userId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKey);//

        //过滤已经选中的购物车中商品
        return cartInfoList.stream().filter(cartInfo -> {
            return CartInfo.YESCHECKED.equals(cartInfo.getIsChecked());
        }).peek(cartInfo -> {
            //单查价格   实时价格
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
            System.out.println("===过滤后的商品" + cartInfo.getSkuId());
        }).collect(Collectors.toList());
    }

    //合并真实用户ID的购物车集合及临时用户ID的购物车集合
    private List<CartInfo> mergeCartList(String userId, String userTempId) {
        //1:判断用户是否有购物车集合
        List<CartInfo> cartInfoListByUserId = getCartInfoList(userId);
        List<CartInfo> cartInfoListByUserTempId = getCartInfoList(userTempId);

        if (!CollectionUtils.isEmpty(cartInfoListByUserId)) {
            //真实用户 的购物车集合有值的
            if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)) {
                //临时用户 真实用户  购物车集合 全都有  大合并
                Map<Long, CartInfo> cartInfoMapByUserId = cartInfoListByUserId.stream().collect(Collectors.toMap(
                        CartInfo::getSkuId, cartInfo -> cartInfo
                ));
                String cacheKeyByUserId = RedisConst.USER_KEY_PREFIX + userId
                        + RedisConst.USER_CART_KEY_SUFFIX;
                for (CartInfo cartInfoByUserTempId : cartInfoListByUserTempId) {
                    CartInfo cartInfoByUserId = cartInfoMapByUserId.get(cartInfoByUserTempId.getSkuId());
                    if (null != cartInfoByUserId) {
                        //1:判断是否存在  追加数量   skuId
                        cartInfoByUserId.setSkuNum(cartInfoByUserId.getSkuNum()
                                + cartInfoByUserTempId.getSkuNum());
                        cartInfoByUserId.setIsChecked(CartInfo.YESCHECKED);
                        //DB  update delete
                        cartInfoMapper.update(cartInfoByUserId, new QueryWrapper<CartInfo>()
                                .eq("user_id", userId).eq("sku_id", cartInfoByUserId.getSkuId()));
                        cartInfoMapper.delete(new QueryWrapper<CartInfo>()
                                .eq("user_id", userTempId)
                                .eq("sku_id", cartInfoByUserTempId.getSkuId()));
                        //Redis
                        redisTemplate.opsForHash().put(cacheKeyByUserId, cartInfoByUserId.getSkuId().toString(),
                                cartInfoByUserId);
                    } else {
                        //2:判断不存在   添加新商品
                        cartInfoMapByUserId.put(cartInfoByUserTempId.getSkuId(), cartInfoByUserTempId);
                        //DB
                        cartInfoByUserTempId.setUserId(userId);
                        cartInfoMapper.update(cartInfoByUserTempId,
                                new QueryWrapper<CartInfo>()
                                        .eq("user_id", userTempId)
                                        .eq("sku_id", cartInfoByUserTempId.getSkuId()));

                        //Redis

                        redisTemplate.opsForHash().put(cacheKeyByUserId, cartInfoByUserTempId.getSkuId().toString(),
                                cartInfoByUserTempId);

                    }
                }
                //删除
                String cacheKeyByUserTempId = RedisConst.USER_KEY_PREFIX + userTempId
                        + RedisConst.USER_CART_KEY_SUFFIX;
                redisTemplate.delete(cacheKeyByUserTempId);
                return new ArrayList<>(cartInfoMapByUserId.values());//强转异常
            } else {
                //临时用户 的购物车集合是null
                return cartInfoListByUserId;
            }
        } else {
            //真实用户 的购物车集合是null
            return cartInfoListByUserTempId;
        }
    }


    //获取用户ID对应的购物车集合   userId:变量
    public List<CartInfo> getCartInfoList(String userId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX + userId
                + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKey);
        //单查价格   实时价格
        cartInfoList.forEach(cartInfo -> {
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        });
        return cartInfoList.stream().sorted((cartInfo1, cartInfo2) -> {
            //返回值   -1 -2 -100  0  1 100
            return cartInfo1.getSkuNum() - cartInfo2.getSkuNum();//升序
        }).collect(Collectors.toList());
    }
}
